package com.zlzlib.librxoknet.base;

import android.util.Log;

import com.zlzlib.librx.TUtil;
import com.zlzlib.librxoknet.converter.FastConverterFactory;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.annotations.NonNull;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;

/**
 * 基础的网络请求
 * Created by zlz on 2019/8/12.
 */
public abstract class BaseRetrofit<T> {

    private final T api;

    public T api() {
        return api;
    }

    /**
     * @Desc: 基础地址
     * @DateTime: 2020/7/14 11:16
     * @Author zlz
     */
    public abstract String baseUrl();

    /**
     * @Desc: 缓存文件夹
     * @DateTime: 2020/7/14 11:16
     * @Author zlz
     */
    protected abstract File cacheFile();

    /**
     * @Desc: 是否有网
     * @DateTime: 2020/7/14 11:16
     * @Author zlz
     */
    protected abstract boolean isNetConnected();

    /**
     * @Desc: 缓存最大大小 单位 b
     * @DateTime: 2020/7/14 11:15
     * @Author zlz
     */
    protected long maxCacheSize() {
        //100mb
        return 1024 * 1024 * 100;
    }

    /**
     * @Desc: 读取超时时间 单位 毫秒
     * @DateTime: 2020/7/14 11:15
     * @Author zlz
     */
    protected long readTimeout() {
        return 10000;
    }

    /**
     * @Desc: 连接超时时间 单位 毫秒
     * @DateTime: 2020/7/14 11:15
     * @Author zlz
     */
    protected long connectTimeout() {
        return 10000;
    }

    /**
     * @Desc: 写入超时时间 单位 毫秒
     * @DateTime: 2020/7/14 11:15
     * @Author zlz
     */
    protected long writeTimeout() {
        return 10000;
    }

    /**
     * @Desc: 允许失败重试
     * @DateTime: 2020/7/14 11:15
     * @Author zlz
     */
    protected boolean isRetryOnConnectionFailure() {
        return true;
    }

    /**
     * @Desc: 最大重试次数
     * @DateTime: 2020/7/14 11:14
     * @Author zlz
     */
    protected int maxTryCount() {
        return 1;
    }

    /**
     * @Desc: 缓存最大效用时长 单位秒  默认设缓存有效期为两天
     * @DateTime: 2020/7/14 10:58
     * @Author zlz
     */
    protected long cacheStaleTime() {
        return 60 * 60 * 24 * 2;
    }

    /**
     * @Desc: 配置OkHttpClient
     * @DateTime: 2020/7/14 10:58
     * @Author zlz
     */
    protected abstract OkHttpClient.Builder settingClient(OkHttpClient.Builder builder);

    /**
     * @Desc: 配置Retrofit
     * @DateTime: 2020/7/14 10:58
     * @Author zlz
     */
    protected Retrofit.Builder settingRetrofit(Retrofit.Builder builder) {
        return builder;
    }

    /**
     * @Desc: 添加公共header
     * @DateTime: 2020/7/14 10:58
     * @Author zlz
     */
    protected Headers.Builder requestHeader() {
        return new Headers.Builder();
    }

    /**
     * @Desc: 是否拦截网络日志
     * @DateTime: 2020/7/14 11:14
     * @Author zlz
     */
    protected abstract boolean isDebug();

    protected Retrofit retrofit;
    private final OkHttpClient client;

    protected BaseRetrofit() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.readTimeout(readTimeout(), TimeUnit.MILLISECONDS)
                .connectTimeout(connectTimeout(), TimeUnit.MILLISECONDS)
                .writeTimeout(writeTimeout(), TimeUnit.MILLISECONDS)
                .retryOnConnectionFailure(isRetryOnConnectionFailure())//默认重试一次，若需要重试N次，则要实现拦截器。
                //添加几个拦截器
                .addInterceptor(retryInterceptor)
                .addInterceptor(cacheInterceptor)
                .addInterceptor(headInterceptor);
        settingClient(builder);
        if (isDebug()) {
            //日志拦截器
            HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new LogInterceptor());
            //setlevel用来设置日志打印的级别，共包括了四个级别：NONE,BASIC,HEADER,BODY
            //BASEIC:请求/响应行
            //HEADER:请求/响应行 + 头
            //BODY:请求/响应行 + 头 + 体
            logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(logInterceptor);
        }
        //添加缓存
        if (null != cacheFile()) {
            //缓存
            builder.cache(new Cache(cacheFile(), maxCacheSize()));
        }
        client = builder.build();
        Retrofit.Builder rBuilder = new Retrofit.Builder()
                .baseUrl(baseUrl())
                .client(client)
                .addConverterFactory(FastConverterFactory.getInstance())//请求的结果转为实体类  只能设置一个转换工厂
//                .addConverterFactory(ScalarsConverterFactory.create())//请求的结果转为string
                //适配RxJava2.0,RxJava1.x则为RxJavaCallAdapterFactory.create()
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create());
        rBuilder = settingRetrofit(rBuilder);
        retrofit = rBuilder.build();
        api = retrofit.create((Class<T>) TUtil.getInstance(this, 0));
    }


    /**
     * 云端响应头拦截器，用来配置缓存策略
     * Dangerous interceptor that rewrites the server's cache-control header.
     * noStore ： 不使用缓存，也不存储缓存
     * onlyIfCached ： 只使用缓存
     * maxAge ：设置最大失效时间，失效则不使用
     * maxStale ：设置最大失效时间，失效则不使用
     * minFresh ：设置最小有效时间，失效则不使用
     * max-stale在请求头设置有效，在响应头设置无效。
     * max-stale和max-age同时设置的时候，缓存失效的时间按最长的算。
     * FORCE_NETWORK ： 强制走网络
     * FORCE_CACHE ：强制走缓存
     */
    /**
     * @Desc: 缓存配置拦截器
     * @DateTime: 2020/7/14 11:03
     * @Author zlz
     */
    private final Interceptor cacheInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!isNetConnected()) {
                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
            }
            Response originalResponse = chain.proceed(request);
            if (isNetConnected()) {
                originalResponse.newBuilder()
                        .header("Cache-Control", "public, max-age=0")
                        // 清除头信息，因为服务器如果不支持，会返回一些干扰信息，不清除下面无法生效
                        .removeHeader("Pragma")
                        .build();
            } else {
                // 无网络时，设置超时
                originalResponse.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + cacheStaleTime())
                        .removeHeader("Pragma")
                        .build();
            }
            return originalResponse;
        }
    };

    /**
     * @Desc: 添加统一头部的拦截器
     * @DateTime: 2020/7/14 11:03
     * @Author zlz
     */
    private final Interceptor headInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Request build = request.newBuilder()
                    .headers(requestHeader().addAll(request.headers()).build())
                    .build();
            return chain.proceed(build);
        }
    };

    /**
     * @Desc: 自定义的，重试N次的拦截器 通过：addInterceptor 设置
     * @DateTime: 2020/7/14 11:04
     * @Author zlz
     */
    private final Interceptor retryInterceptor = new Interceptor() {
        private int retryNum = 1;

        @Override
        public Response intercept(@NonNull Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            while (!response.isSuccessful() && retryNum < maxTryCount()) {
                retryNum++;
                response = chain.proceed(request);
            }
            return response;
        }
    };

    /**
     * @Desc: 日志拦截器
     * @DateTime: 2020/7/14 11:03
     * @Author zlz
     */
    private final class LogInterceptor implements HttpLoggingInterceptor.Logger {
        @Override
        public void log(String s) {
            //post 的请求体数据会转码 ， 这里日志进行一次解码  方便观看
            try {
                s = URLDecoder.decode(s, "UTF-8");
            } catch (Exception ignored) {
            }
            logPrint(s);
        }
    }

    /**
     * @Desc: 日志输出
     * @DateTime: 2020/7/14 10:57
     * @Author zlz
     */
    protected void logPrint(String log) {
        Log.i("BaseRetrofit", log);
    }

    /**
     * @Desc: 获得okhttp的请求端
     * @DateTime: 2020/7/14 10:56
     * @Author zlz
     */
    public OkHttpClient getClient() {
        return client;
    }
}
